use actix_identity::Identity;
use anyhow::{anyhow, Result};

use rbatis::core::db::DBExecResult;
use rbatis::crud::CRUD;
use rbatis::plugin::page::{Page, PageRequest};
use rbatis::wrapper::Wrapper;
use rbatis::{sql, DateTimeNative};
use rbson::{Bson, Uuid};

use crypt_util::Claims;
use fast_common::base::base_service::BaseService;
use fast_common::common::orm_config::RB;
use fast_common::models::menu::Menu;
use fast_common::models::role::Role;

use fast_common::models::user::{ResetPasswordReq, SysUser, UserLoginVo, UserRoleMenuVo, UserVo};
use fast_common::models::user_role::{UserRole, UserRolesReq};
use fast_common::utils::crypt_util;
use fast_common::utils::crypt_util::Crypt;
use fast_common::utils::redis_util::REDIS_UTIL;

pub struct UserService {}

impl BaseService for UserService {
    type Model = SysUser;

    fn get_wrapper() -> Wrapper {
        RB.new_wrapper_table::<Self::Model>()
    }
}

impl UserService {
    pub async fn add(mut user: SysUser) -> Result<DBExecResult> {
        user.create_time = Some(DateTimeNative::now());
        let string = user.password.unwrap_or_else(|| "111111".to_string());
        user.password = Some(Crypt::encrypt(&string)?);
        dbg!("{}测试数据", &user);
        let result = Self::save(user).await;
        result
    }

    pub async fn update(user: SysUser) -> Result<u64> {
        let wrapper = Self::get_wrapper();
        let result = RB.update_by_wrapper(&user, wrapper, &[]).await?;
        Ok(result)
    }

    pub async fn delete(_user: SysUser) -> Result<u64> {
        let wrapper = Self::get_wrapper();
        let result = RB.remove_by_wrapper::<SysUser>(wrapper).await?;
        Ok(result)
    }

    pub async fn list(arg: UserVo) -> Result<Page<SysUser>> {
        let mut wrapper = RB.new_wrapper();
        wrapper = wrapper
            .do_if(false, |wrapper| wrapper.eq("id", &arg.id))
            .do_if(false, |wrapper| wrapper.like_left("user_name", &arg.user_name))
            .do_if(false, |wrapper| wrapper.eq("age", &arg.age))
            .do_if(false, |wrapper| {
                wrapper.gt("create_time", &arg.start_time).and().le("create_time", &arg.end_time)
            });

        let page_request = PageRequest::new(arg.page_num.unwrap_or(1), arg.page_size.unwrap_or(10));
        let page: Page<SysUser> = RB.fetch_page_by_wrapper(wrapper, &page_request).await?;
        Ok(page)
    }

    pub async fn login(user_login_vo: UserLoginVo, identity: Identity) -> Result<UserRoleMenuVo> {
        let mut wrapper = RB.new_wrapper();
        if user_login_vo.user_name.is_none()
            || user_login_vo.password.is_none()
            || user_login_vo.bar_code.is_none()
        {
            Err(anyhow!("用户名为空或密码为空或验证码为空"))
        } else {
            let user_name = user_login_vo.user_name.unwrap();
            let user_password = user_login_vo.password.unwrap();
            let bar_code = user_login_vo.bar_code.unwrap();
            let result = verify_bar_code(&user_name, bar_code).await;
            if result.is_err() {
                return Err(anyhow!("验证码过期或验证码错误"));
            }

            wrapper = wrapper.eq("user_name", user_name);
            let user_result = RB.fetch_by_wrapper::<SysUser>(wrapper).await;
            match user_result {
                Ok(u) => {
                    let user_name = u.clone().user_name.unwrap();

                    let roles = get_role_by_user(u.user_id.unwrap()).await?;
                    let menus = get_menu_by_user(&roles).await?;
                    let claims = Claims::new(
                        u.user_id.unwrap(),
                        user_name.clone(),
                        roles.0.clone(),
                        menus.clone(),
                        10000,
                    );
                    let access_token_value = claims.encode()?;
                    let access_token = Uuid::new().to_string();

                    if u.password.unwrap().eq(&user_password) {
                        //成功后删除redis中的验证码
                        let _ = REDIS_UTIL.delete(user_name.clone().as_str()).await;
                        let _ = REDIS_UTIL
                            .set_string(access_token.as_str(), access_token_value.clone())
                            .await;

                        let user_role_menu_vo = UserRoleMenuVo {
                            user_id: (u.user_id),
                            user_name: (u.user_name.clone()),
                            access_token: Some(access_token),
                            roles: Some(roles.0),
                            menus: Some(menus),
                        };
                        identity.remember(access_token_value);
                        Ok(user_role_menu_vo)
                    } else {
                        Err(anyhow::Error::msg("密码或账号错误"))
                    }
                }
                Err(e) => Err(anyhow!(format!("{},{}", "登录失败", e))),
            }
        }
    }

    pub async fn auth_role(user_roles: UserRolesReq) -> Result<()> {
        for role_id in user_roles.roles_id {
            let user_role = UserRole {
                id: None,
                user_id: Some(user_roles.user_id),
                role_id: Some(role_id),
                default_role_id: None,
                create_time: Some(DateTimeNative::now()),
            };
            let _result = RB.save(&user_role, &[]).await?;
        }
        Ok(())
    }

    pub async fn reset_password(reset_password: ResetPasswordReq) -> Result<()> {
        Ok(())
    }
}

async fn verify_bar_code(user_name: &str, bar_code: String) -> Result<String> {
    let redis_result = REDIS_UTIL.get_string(user_name).await;
    match redis_result {
        Ok(ret) => {
            if bar_code.to_lowercase() != ret.to_lowercase() {
                Err(anyhow!("无效的验证码"))
            } else {
                Ok("".to_string())
            }
        }
        Err(err) => Err(anyhow!(err.to_string())),
    }
}

async fn get_role_by_user(user_id: u64) -> Result<(Vec<Role>, u64)> {
    let result = RB.fetch::<Vec<Role>>(
        "select a.*,b.default_role_id  from role a left join user_role b on a.role_id = b.role_id ", vec![Bson::UInt64(user_id)]).await?;

        let sql = format!(
            "select default_role_id ,user_id  from user_role where user_id = {}{}",
            user_id, " group by user_id");
    let default_role_id = RB
        .fetch::<u64>(sql.as_str(),vec![])
        .await?;
    Ok((result, default_role_id))
}

async fn get_menu_by_user(role: &(Vec<Role>, u64)) -> Result<Vec<Menu>> {
    let result = RB.fetch::<Vec<Menu>>(
        "select a.* from menu a  left join role_menu b  on a.menu_id = b.menu_id where b.role_id = ?", vec![Bson::UInt64(role.1)]).await;
    result.map_err(|e| anyhow!(e))
}
